package com.example.springboot_demo.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.example.springboot_demo.dto.Goods;
import com.example.springboot_demo.dto.request.GoodsRequest;
import com.example.springboot_demo.mapper.GoodsMapper;
import com.example.springboot_demo.service.GoodsService;
import com.example.springboot_demo.utils.AjaxResult;
import com.example.springboot_demo.utils.PageUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sun.org.apache.bcel.internal.generic.NEW;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <P> @Author: SongKeCheng
 * <P> Type: Class
 * <P> Description: goods 的逻辑层
 * <P> Date: 2024/6/22:10:02
 */

@SuppressWarnings({"unchecked", ""})
@Service
public class GoodsServiceImpl implements GoodsService {
    private static final Logger log = LoggerFactory.getLogger(GoodsServiceImpl.class);


    @Autowired
    private GoodsMapper goodsMapper;

    @Autowired
    private RedisTemplate<String, Object> template;


    /**
     * 1.先查询缓存，
     * 如有缓存有，则直接返回；
     * 如果缓存，查询数据库
     * 2. 查询数据库
     */
    @Override
    public AjaxResult findGoods(GoodsRequest goodsRequest) {

        PageUtils pageUtils;

        //根据分页参数 build key
        String key = buildPageKey(goodsRequest);

        Object jsonData = template.opsForValue().get(key);


        //如果数据不为空 进行转换后 直接返回
        if (!ObjectUtils.isEmpty(jsonData)) {
            pageUtils = getData(new TypeReference<PageUtils>() {
            }, jsonData);
            return AjaxResult.success(pageUtils);
        }


        //如果缓存没有，则查询数据库，把查询到的数据，放入到 redis 缓存中
        pageUtils = findDB(goodsRequest);
        template.opsForValue().set(key, pageUtils, 2, TimeUnit.MINUTES);
        return AjaxResult.success(pageUtils);
    }


    private String buildPageKey(GoodsRequest goodsRequest) {
        //goodsPage:1:2
        //goodsPage:页码：每页数量
        final String keyPre = "goodsPage";
        String key = new StringBuilder().append(keyPre)
                .append(":")
                .append(goodsRequest.getPageNum())
                .append(":")
                .append(goodsRequest.getPageSize())
                .toString();

        return key;
    }

    /**
     * 根据传入的类型 把封装的 data 数据获取并且转为这个类型
     *
     * @param typeReference 指定返回类型
     * @return T
     **/
    public <T> T getData(TypeReference<T> typeReference, Object data) {
        String jsonString = JSON.toJSONString(data);
        return JSON.parseObject(jsonString, typeReference);
    }
    //使用示例：getData(new TypeReference<PageUtils>(){},redisData);


    private PageUtils findDB(GoodsRequest goodsRequest) {
        PageHelper.startPage(goodsRequest.getPageNum(), goodsRequest.getPageSize());
        timeSleep(3);
        List<Goods> goodsList = goodsMapper.findGoods(goodsRequest);


        PageInfo<Goods> pageAll = PageInfo.of(goodsList);
        PageUtils pageUtils = new PageUtils(pageAll);
        return pageUtils;
    }


    public static void timeSleep(int time) {
        try {
            TimeUnit.SECONDS.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public AjaxResult deleteGoods(GoodsRequest goodsRequest) {
        int i = goodsMapper.deleteByPrimaryKey(goodsRequest.getId());
        if (i > 0) {
            return AjaxResult.success("删除成功");
        } else {
            return AjaxResult.error("删除失败,可能不存在此条记录");
        }
    }

    @Override
    public AjaxResult updateGoods(GoodsRequest goodsRequest) {
        if (ObjectUtils.isEmpty(goodsRequest.getId())) {
            throw new NullPointerException("更新操作 主键id不能为空");
        }
        Goods goods = new Goods();
        BeanUtils.copyProperties(goodsRequest, goods);
        int i = goodsMapper.updateByPrimaryKeySelective(goods);
        if (i > 0) {
            return AjaxResult.success("更新成功");
        } else {
            return AjaxResult.error("更新失败");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult addGoods(GoodsRequest goodsRequest) throws IOException {
        Goods goods = new Goods();
        BeanUtils.copyProperties(goodsRequest, goods);
        //checkName();
        int i = goodsMapper.insertSelective(goods);
        //if (i > 0) {
        //    return AjaxResult.success("新增成功");
        //} else {
        //    return AjaxResult.error("新增失败");
        //}

        try {
            testTransactional1(goodsRequest);
        } catch (IOException e) {
            e.printStackTrace();
            throw new IOException();
        }
        return null;
    }
    @Autowired
    private GoodsService goodsService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult testTransactional1(GoodsRequest goods) throws IOException {
        this.testTransactional2(goods);
        //throw new IOException();
        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult testTransactional2(GoodsRequest goodsRequest) throws IOException {
        Goods goods = new Goods();
        BeanUtils.copyProperties(goodsRequest, goods);
        goodsMapper.insertSelective(goods);
        log.info("新生成的id是 {}",goods.getId());
        int i = 1/0;
        //throw new IOException();
        return null;
    }
}
